import { mapState } from 'vuex'
import Wrap from './Wrap'
import { mouseStatus, canvasId, nestComponentTags } from '../../lib/const'
import {
  addSnapshot,
  getIsComponentStyleChange,
  setSelectedComponent,
  getComponentListByKeys,
  setMultipleKeys,
  deepCopy,
  parse,
  ergodicList,
  removeComponentByKey,
  updateComponentKey,
  getComponentByKey,
  getOffsetByCanvas,
} from '../../lib/utils'
// import render from "../../lib/render"
import ComponentRender from './ComponentRender'
import Contextmenu from './Contextmenu'
import Marking from './Marking'
import initEvent from './event'
import EventBus from '../../EventBus'
import Multiple from './Multiple'
import { componentToPx, componentToPercentage } from '../../lib/unit'
import {
  getBaseAnalysisComponent,
  setAnalysisComponentListLinkage,
  getAllAnalysisComponentByEditType,
} from '../../lib/analysisData'
import { getTableList } from '../../lib/table'
import { getDateList } from '../../lib/date'
import Detailed from '../Detailed'
import './index.less'
import { stopAnimateByComponent } from '../../lib/animate'

let selectedMouseOffset = {} // 当鼠标按下时, 鼠标距离当前点击元素左上角的偏移
let mouseZoomStart = {}

let isMouseDragDown = false // 是否按住组件(非zoom-point),准备拖拽
let isMouseZoomDown = false // 是否按住zoom-point,准备拖拽zoom-point
let isMultipleDown = false // 是否按住画布,准备拖动鼠标开始绘制多选框
let selectZoomIndex // 当前选中的zoom-point
let selectDropComponent = null // 当前准备放入组件的组件
let dragSelectedComponentKey = ''

const ADD_KEY = '0000'
export default {
  data() {
    return {
      canvasComponentList: [],
      mouseStatus,
      isContextmenuShow: false,
      contextmenuPosition: {},
      contextmenuType: 'component',
      canvasId,
      isCanvasDrop: false,
      multipleStartPosition: {},
      multipleEndPosition: {},
      isMultipleShow: false,
      scrollOffset: {
        x: 0,
        y: 0,
        scrollTop: 0,
        scrollLeft: 0,
      },
    }
  },
  computed: {
    ...mapState('lowCode', {
      mouseState: (state) => state.mouseState,
      selectedComponent: (state) => state.selectedComponent,
      multipleKeys: (state) => state.multipleKeys,
    }),
  },
  components: {
    Wrap,
    Contextmenu,
    Marking,
    Multiple,
    Detailed,
  },
  created() {
    initEvent(this)
  },
  methods: {
    handleDrop(event) {
      this.isCanvasDrop = false
      event.preventDefault()
      if (this.mouseState !== mouseStatus.ADD_DRAG) {
        this.$store.commit('lowCode/setMouseStatusChange', mouseStatus.DEFAULT)
        return false
      }

      // console.log(event, event.dataTransfer.getData("data"))
      const { data, mouseOffset, type } = parse(event.dataTransfer.getData('data'))
      let component = null

      if (type === 'analysis') {
        component = getBaseAnalysisComponent(data)
      } else {
        component = data
      }
      component.key = updateComponentKey(component.id)
      // 组件原点是左上角
      // 因此,组件坐标为 offsetX - 当前鼠标距离当前组件原点的距离
      const { x, y } = mouseOffset
      component.style.left = event.offsetX - x
      component.style.top = event.offsetY - y
      // 如果鼠标释放时,鼠标的位置还在isDrap的组件内,那么就将组件放入isDrap的组件内
      if (selectDropComponent) {
        this.addChildItem(selectDropComponent, component, 'add')
      }

      this.setCanvasComponentList()
      this.setSelectedComponent()
      setMultipleKeys()

      this.saveSnapshot({
        canvasComponentList: this.canvasComponentList,
      })
      this.$store.commit('lowCode/setMouseStatusChange', mouseStatus.DEFAULT)

      setTimeout(() => {
        this.setSelectedComponent(1, {
          data: component,
        })
      })
    },
    handleDragover(event) {
      event.preventDefault()
      if (this.mouseState !== mouseStatus.ADD_DRAG) {
        this.$store.commit('lowCode/setMouseStatusChange', mouseStatus.DEFAULT)
        this.isCanvasDrop = false
        return false
      }
      this.getRadial(event.offsetX, event.offsetY, ADD_KEY)
    },
    /**
     * 结束当前组件的动画
     */
    stopAnimate() {
      this.$store.commit('lowCode/setAnimateRunStatus', false)
      this.selectedComponent.key && stopAnimateByComponent(this.selectedComponent)
    },
    // 点击组件
    handleComponentMouseDown(event, item) {
      event.preventDefault()
      event.stopPropagation()
      this.stopAnimate()
      const { type, index } = event.target.dataset
      let museStatus = mouseStatus.DEFAULT
      // 如果没有这个定时器，在input修改数据后，立即点击组件，会有触发selectedComponent(即input)change事件的bug
      // setTimeout(()=> {
      // this.setSelectedComponent(1, {
      //   data: item//getComponentByKey(item.key),
      // })
      if (event.button === 2) {
        this.contextmenuPosition = {
          left: `${event.clientX}px`,
          top: `${event.clientY}px`,
          offsetX: event.offsetX,
          offsetY: event.offsetY,
          clientX: event.clientX,
          clientY: event.clientY,
        }
        this.contextmenuType = 'component'
        this.isContextmenuShow = true
        // 如果当前没有选中组件, 那么就选中当前组件
        // if(this.multipleKeys.length === 0){
        this.setSelectedComponent(1, {
          data: item, // getComponentByKey(item.key),
        })
        // }
      } else {
        // 必须要先选中组件,zoom-point才会显示
        if (type === 'zoom-point') {
          this.setSelectedComponent(1, {
            data: item, // getComponentByKey(item.key),
          })
          isMouseZoomDown = true
          // 开始拖拽时的初始位置
          mouseZoomStart = {
            x: event.clientX,
            y: event.clientY,
          }
          museStatus = mouseStatus.ZOOM
          selectZoomIndex = index
        } else if (type === 'drag-wrap') {
          dragSelectedComponentKey = item.key
          if (this.multipleKeys.length <= 1) {
            this.setSelectedComponent(1, {
              data: item, // getComponentByKey(item.key),
            })
          }

          selectedMouseOffset = {
            x: event.clientX,
            y: event.clientY,
          }
          museStatus = mouseStatus.DRAG
          isMouseDragDown = true
        } else {
          this.setSelectedComponent(1, {
            data: item, // getComponentByKey(item.key),
          })
          // museStatus = mouseStatus.ADD_DRAG
        }
      }
      // })

      this.$store.commit('lowCode/setMouseStatusChange', museStatus)
    },
    // 点击画布
    handleMouseDown(event) {
      event.preventDefault()
      // event.stopPropagation()
      // 如果是右键点击,则显示右键菜单
      if (event.button === 2) {
        this.contextmenuPosition = {
          left: `${event.clientX}px`,
          top: `${event.clientY}px`,
          offsetX: event.offsetX,
          offsetY: event.offsetY,
          clientX: event.clientX,
          clientY: event.clientY,
        }
        this.contextmenuType = 'map'
        this.isContextmenuShow = true
        this.setSelectedComponent()
      } else {
        this.stopAnimate()
        this.isContextmenuShow = false
        const { type, index } = event.target.dataset
        // 如果点击的是画布,则将已选择组件置空,并显示多选绘制框
        if (type === 'map') {
          this.setSelectedComponent()
          setMultipleKeys()

          // museStatus = mouseStatus.DEFAULT
          // 如果当前多选框没有显示
          if (!this.isMultipleShow) {
            // 显示多选框
            this.isMultipleShow = true

            isMultipleDown = true
            // 并记录当前位置
            this.multipleStartPosition = {
              clientX: event.clientX,
              clientY: event.clientY,
              offsetX: event.offsetX,
              offsetY: event.offsetY,
            }
            this.scrollOffset = {
              x: this.scrollOffset.x,
              y: this.scrollOffset.y,
              scrollLeft: this.scrollOffset.x,
              scrollTop: this.scrollOffset.y,
            }
            // console.log(this.scrollOffset)
            // vm.scrollOffset.scrollLeft = scrollLeft
            // vm.scrollOffset.scrollTop = scrollTop
            // vm.scrollOffset.x = scrollLeft
            // vm.scrollOffset.y = scrollTop
          } else {
            // 隐藏多选框
            this.isMultipleShow = false
            isMultipleDown = false
            // 并清空之前的位置信息
            this.multipleStartPosition = {}
            this.multipleEndPosition = {}
          }
        } else {
        }
      }
    },
    handleMouseMove(event) {
      event.preventDefault()
      event.stopPropagation()
      const { type } = event.target.dataset
      // this.$store.commit("lowCode/setMouseStatusChange", mouseStatus.ADD_DRAG)
      // 如果正在拖拽组件
      if (isMouseDragDown) {
        // 新位置 = 当前鼠标距离画布左上角的位置 - 偏移量(即鼠标位置距离当前选中元素原点的偏移量)
        const { x, y } = selectedMouseOffset
        const { canvasComponentList, multipleKeys } = this
        const selectedComponents = getComponentListByKeys(canvasComponentList, multipleKeys)
        selectedComponents.forEach((component) => {
          const { left, top } = component.style
          // 获取鼠标的偏移量
          const offsetX = event.clientX - x
          const offsetY = event.clientY - y
          // 获取新坐标
          const newLeft = left + offsetX
          const newTop = top + offsetY
          const { left: pLeft, top: pTop } = componentToPercentage({
            ...component.style,
            left: newLeft,
            top: newTop,
          })
          component.style.left = pLeft
          component.style.top = pTop
        })

        // 获取当前鼠标下方的所有组件,并将最上层的组件高亮
        // console.log(event)
        this.getRadial(event.clientX, event.clientY, dragSelectedComponentKey)

        // 然后将现在的位置赋值给初始位置
        selectedMouseOffset = {
          x: event.clientX,
          y: event.clientY,
        }
      }
      // 如果正在拉伸缩放左键
      if (isMouseZoomDown) {
        // typeList.includes(type) &&
        const selectedComponent = this.selectedComponent
        const { x, y } = mouseZoomStart
        const offsetX = event.clientX - x
        const offsetY = event.clientY - y
        let newWidth
        let newHeight
        let newLeft
        let newTop
        const { width, height, top, left } = componentToPx(selectedComponent.style)
        switch (selectZoomIndex) {
          case '0': // left, top
            newWidth = width - offsetX
            newHeight = height - offsetY
            newLeft = left + offsetX
            newTop = top + offsetY
            break
          case '1': // top
            newWidth = width
            newHeight = height - offsetY
            newLeft = left
            newTop = top + offsetY
            break
          case '2':
            newWidth = width + offsetX
            newHeight = height - offsetY
            newLeft = left
            newTop = top + offsetY
            break
          case '3':
            newWidth = width + offsetX
            newHeight = height
            newLeft = left
            newTop = top
            break
          case '4':
            newWidth = width + offsetX
            newHeight = height + offsetY
            newLeft = left
            newTop = top
            break
          case '5':
            newWidth = width
            newHeight = height + offsetY
            newLeft = left
            newTop = top
            break
          case '6':
            newWidth = width - offsetX
            newHeight = height + offsetY
            newLeft = left + offsetX
            newTop = top
            break
          case '7':
            newWidth = width - offsetX
            newHeight = height
            newLeft = left + offsetX
            newTop = top
            break
          default:
            break
        }
        // 然后将现在的位置赋值给初始位置
        mouseZoomStart = {
          x: event.clientX,
          y: event.clientY,
        }

        const {
          width: pWidth,
          height: pHeight,
          top: pTop,
          left: pLeft,
        } = componentToPercentage({
          ...selectedComponent.style,
          width: newWidth,
          height: newHeight,
          top: newTop,
          left: newLeft,
        })
        const newComponent = {
          ...selectedComponent,
          style: {
            ...selectedComponent.style,
            width: pWidth,
            height: pHeight,
            left: pLeft,
            top: pTop,
          },
        }
        this.$store.commit('lowCode/setWrapStyle', newComponent.style)
      }
      // 如果点击了画布,正在多选组件
      if (isMultipleDown) {
        // 更新结束位置
        this.multipleEndPosition = {
          clientX: event.clientX,
          clientY: event.clientY,
          offsetX: event.offsetX,
          offsetY: event.offsetY,
        }
      } else {
        // this.$store.commit("lowCode/setSelectedComponent", {});
      }
    },
    handleMouseUp(event) {
      const { type, index } = event.target.dataset
      isMouseDragDown = false
      isMouseZoomDown = false
      selectZoomIndex = undefined

      // 如果鼠标释放时,鼠标的位置还在isDrap的组件内,那么就将组件放入isDrap的组件内
      if (selectDropComponent) {
        this.addChildItem(selectDropComponent, this.selectedComponent)
      }
      this.resetMultiple()
      // else if(selectDropComponent === -1) {
      //   // 添加到最外层
      //   this.setCanvasComponentList(1, this.selectedComponent)
      // }

      ergodicList(this.canvasComponentList, (element) => {
        if (element.key === this.selectedComponent.key) {
          element = deepCopy(this.selectedComponent)
        }
      })

      this.$store.commit('lowCode/setMouseStatusChange', mouseStatus.DEFAULT)
      const isComponentChange = getIsComponentStyleChange()
      if (isComponentChange) {
        // 发生更改
        this.saveSnapshot({
          canvasComponentList: this.canvasComponentList,
        })
      }
      if (event.button !== 2 && type !== 'contextmenu') {
        this.isContextmenuShow = false
      }
      // this.$store.commit("lowCode/setMouseStatusChange", mouseStatus.DEFAULT)
      event.preventDefault()
      event.stopPropagation()
    },
    handleContextmenu(event) {
      event.preventDefault()
    },
    /**
     * 重置多选框
     */
    resetMultiple() {
      if (isMultipleDown) {
        this.$refs.multipleRef.setSelectComponents()
        this.isMultipleShow = false
        this.multipleStartPosition = {}
        this.multipleEndPosition = {}
      }
      isMultipleDown = false
      // this.scrollOffset = {
      //   x: 0,
      //   y: 0,
      //   scrollTop: 0,
      //   scrollLeft: 0
      // }
    },
    /**
     * 将当前组件作为子组件添加入drop组件内
     * @param {*} dropItem 接收当前组件的组件
     * @param { Component } selectComponent  当前组件
     * @param {*} type  添加方式, 'add', 'move'
     */
    addChildItem(dropItem, selectComponent, type = 'move') {
      const { canvasComponentList, multipleKeys } = this
      if (type === 'add') {
        this.appendItem(dropItem, selectComponent, (type = 'add'))
      } else {
        // 当前选中的所有组件
        const selectedComponents = getComponentListByKeys(canvasComponentList, multipleKeys)
        selectedComponents.forEach((componentItem) => {
          this.appendItem(dropItem, componentItem, (type = 'move'))
        })
      }
    },
    appendItem(dropItem, selectComponent, type = 'move') {
      let children
      let dropChild
      const { canvasComponentList } = this
      const { id, style, key } = selectComponent
      if (dropItem === -1) {
        // 说明应当放到最外层
        dropChild = {
          key: canvasId,
        }
        children = canvasComponentList
      } else {
        dropChild = dropItem
        const { value, list } = dropChild.props
        children = list.find((item) => item.value === value).children
      }
      // 当前鼠标位置
      let left
      let top
      if (type === 'move') {
        const { offsetLeft, offsetTop } = getOffsetByCanvas(document.getElementById(key))
        left = offsetLeft
        top = offsetTop
      } else if (type === 'add') {
        left = style.left
        top = style.top
      }

      const { offsetLeft: parentLeft, offsetTop: parentTop } = getOffsetByCanvas(document.getElementById(dropChild.key))
      const newLeft = left - parentLeft
      const newTop = top - parentTop
      const tempKey = updateComponentKey(id)
      const component = deepCopy({
        ...selectComponent,
        key: tempKey,
        style: {
          ...style,
          ...componentToPercentage({
            ...style,
            left: newLeft,
            top: newTop,
          }),
        },
      })
      children.push(component)
      // 然后将canvasComponentList里的selectedComponent删除
      removeComponentByKey(canvasComponentList, key)
      component.key = key
      // 清空selectedComponent
      this.setSelectedComponent()
      // setMultipleKeys()
      ergodicList(canvasComponentList, (element) => {
        element.isDrop = false
      })
      this.isCanvasDrop = false
      selectDropComponent = null
      this.setCanvasComponentList()
    },
    /**
     * 更新业务组件相关数据
     */
    updateAnalysisComponentData() {
      // 获取所有业务组件
      const analysisComponentList = getAllAnalysisComponentByEditType(true)
      // 更新下拉框的表和字段的列表
      getTableList(analysisComponentList)
      // 更新日期选择器的表和字段的列表
      getDateList(analysisComponentList)
      // 更新所有业务组件联动设置
      setAnalysisComponentListLinkage(analysisComponentList)
    },
    /**
     * 保存快照
     */
    saveSnapshot(data) {
      this.updateAnalysisComponentData()

      const { pageSetting, canvasComponentList } = this.$store.state.lowCode
      const saveData = {
        pageSetting: data.pageSetting || pageSetting,
        canvasComponentList: data.canvasComponentList || canvasComponentList,
      }
      addSnapshot('all', deepCopy(saveData))
    },
    /**
     * 修改componentListChange
     * @param {*} type 修改类型,1: push,2: 替换整个data
     * @param {*} data push的item或者新数据
     * @param {*} isUpdate 是否需要更新
     */
    setCanvasComponentList(type, data, isUpdate) {
      switch (type) {
        case 1:
          this.canvasComponentList.push(data)
          break
        case 2:
          // this.$set(this.canvasComponentList, index, data)
          this.canvasComponentList = data
          if (isUpdate) {
            this.$forceUpdate()
            // 如果此时有选择组件,那么还需要给selectedComponent重新赋值(双向绑定)
            if (this.selectedComponent.key) {
              const selectedComponent = getComponentByKey(this.canvasComponentList, this.selectedComponent.key)
              // 如果现在组件列表里搜不到已选择组件,就将当前组件置空
              if (selectedComponent) {
                this.setSelectedComponent(1, {
                  data: selectedComponent,
                })
              } else {
                this.setSelectedComponent()
              }
            }
          }
          break
        default:
        // this.canvasComponentList = data
      }

      // 向其他组件分发组件变动
      EventBus.$emit('canvasComponentListChange', this.canvasComponentList)
      this.$store.commit('lowCode/setCanvasComponentList', this.canvasComponentList)
    },
    /**
     * 修改selectedComponent
     * @param {*} type 修改类型,1: 修改,2: 清空
     * @param {*} option 修改的数据
     */
    setSelectedComponent(type, option = {}) {
      // 过滤无效修改
      const oldComponent = this.selectedComponent
      const newComponent = option.data
      // !如果之前和现在都是没有选中组件
      if (!(!oldComponent.key && !newComponent)) {
        // 获取所有业务组件,来更新表和字段的列表
        this.updateAnalysisComponentData(true)
      }
      setSelectedComponent(type, option)
    },
    /**
     * 获取当前鼠标坐标下的所有组件
     * @param {*} mouseAbsLeft 鼠标x值(绝对位置)
     * @param {*} mouseAbsTop 鼠标y值(绝对位置)
     * @param {*} selectKey 当前key
     */
    getRadial(mouseAbsLeft, mouseAbsTop, selectKey) {
      // console.log(mouseLeft,mouseTop)
      const { canvasComponentList } = this
      // 所有同级或者同级的子组件
      const componentList = canvasComponentList
      const radialComponentList =
        this.getComponentAddress(
          componentList,
          {
            left: mouseAbsLeft,
            top: mouseAbsTop,
          },
          selectKey,
          []
        ) || []
      let isCanvasDrop = false
      // console.log(radialComponentList)
      if (radialComponentList.length === 0) {
        // 说明当前鼠标在最外层

        // 如果组件本身就在最外层,那么不做处理
        if (canvasComponentList.find((element) => element.key === selectKey)) {
          selectDropComponent = null
          isCanvasDrop = false
        } else {
          // 将组件放到最外层
          selectDropComponent = -1
          isCanvasDrop = true
        }
      } else {
        const dropComponent = radialComponentList[radialComponentList.length - 1]
        // 判断要drop的组件是不是自己的父节点
        const { list, value } = dropComponent.props
        const children = ((list || []).find((item) => value === item.value) || {}).children
        if ((children || []).find((item) => item.key === selectKey)) {
          // 要drop的组件是自己的父节点
          selectDropComponent == null
        } else {
          dropComponent.isDrop = true
          selectDropComponent = dropComponent
        }
      }
      this.isCanvasDrop = isCanvasDrop
    },
    /**
     * 获取当前鼠标下的所有c-tabs组件(不包括自己)
     * @param {*} list
     * @param {*} mouse
     * @param {*} selectKey
     * @param {*} radialComponentList
     * @returns
     */
    getComponentAddress(list, mouse, selectKey, radialComponentList) {
      list.forEach((element) => {
        const { tag, style, props, key } = element
        element.isDrop = false
        if (nestComponentTags.includes(tag)) {
          const { width, height } = componentToPx(style)
          const { list, value } = props
          const children = ((list || []).find((item) => value === item.value) || {}).children
          const bool = this.getMouseIsStayWrap(
            selectKey,
            {
              width,
              height,
              key,
            },
            mouse
          )
          // 当前元素是否在element范围内,且element不是当前元素
          if (bool && element.key !== selectKey) {
            radialComponentList.push(element)
          }

          children && this.getComponentAddress(children, mouse, selectKey, radialComponentList)
        } else {
        }
      })
      return radialComponentList
    },
    /**
     * 判断鼠标在不在wrap里
     * @param {*} selectKey
     * @param {*} wrap
     * @param {*} mouse
     * @returns
     */
    getMouseIsStayWrap(selectKey, wrap, mouse) {
      let mouseLeft
      let mouseTop
      // console.log(selectKey, wrap, mouse)
      if (ADD_KEY === selectKey) {
        const { left, top } = mouse
        mouseLeft = left
        mouseTop = top
      } else {
        const { offsetLeft, offsetTop } = getOffsetByCanvas(document.getElementById(selectKey)) // mouse
        mouseLeft = offsetLeft
        mouseTop = offsetTop
      }

      const { width, height, key } = wrap
      const { offsetLeft: left, offsetTop: top } = getOffsetByCanvas(document.getElementById(key))
      const minLeft = left
      const minTop = top
      const maxLeft = left + width
      const maxTop = top + height
      // console.log(minLeft, mouseLeft, maxLeft)
      return mouseLeft >= minLeft && mouseLeft <= maxLeft && mouseTop >= minTop && mouseTop <= maxTop
    },
    hideContextmenu() {},
  },
  render(h) {
    const {
      mouseState,
      mouseStatus,
      selectedComponent,
      isContextmenuShow,
      multipleKeys,
      contextmenuPosition,
      canvasComponentList,
      isCanvasDrop,
      isMultipleShow,
      multipleStartPosition,
      multipleEndPosition,
      scrollOffset,
      contextmenuType,
      handleDrop,
      handleDragover,
      handleMouseDown,
      handleMouseMove,
      handleMouseUp,
      handleContextmenu,
      handleComponentMouseDown,
    } = this
    return (
      <div
        id={canvasId}
        class={`canvas ${isCanvasDrop ? 'drop' : ''} ${
          mouseState === mouseStatus.DRAG || mouseState === mouseStatus.ZOOM ? 'dragenter' : ''
        }`}
        onDrop={handleDrop}
        ondragover={handleDragover}
        onMousedown={handleMouseDown}
        onMousemove={handleMouseMove}
        onMouseup={handleMouseUp}
        onContextmenu={handleContextmenu}
      >
        <div class={`position-box ${mouseState === mouseStatus.ADD_DRAG ? 'dragenter' : ''}`}></div>
        <div class="wrap-list" data-type="map">
          <ComponentRender
            list={canvasComponentList}
            isEdit={true}
            multipleKeys={multipleKeys}
            selectedComponent={selectedComponent}
            handleComponentMouseDown={handleComponentMouseDown}
          />
          <Marking />
        </div>
        <Contextmenu type={contextmenuType} isShow={isContextmenuShow} position={contextmenuPosition} />
        <Multiple
          ref="multipleRef"
          multipleStartPosition={multipleStartPosition}
          multipleEndPosition={multipleEndPosition}
          isShow={isMultipleShow}
          scrollOffset={scrollOffset}
        />
        <Detailed ref="detailedRef" />
      </div>
    )
  },
}
